package util

import (
    "fmt"
    "regexp"
    "strings"

    "cing.io/cing-api/planner"
    "cing.io/cing-api/task"
)

const (
    AllSinger       = "AllSinger"
    NoSinger        = "NoSinger"
    OneRandomSinger = "OneRandomSinger"
    Sharding        = "Sharding"
    SpecificSinger  = "SpecificSinger"
    TheFirstSinger  = "TheFirstSinger"
)

var selectorNameRegexpStr = fmt.Sprintf(`^\s*(?P<selector>(?:%s)|(?:%s)|(?:%s)|(?:%s)|(?:%s)|(?:%s)).*$`,
    AllSinger, NoSinger, OneRandomSinger, Sharding, SpecificSinger, TheFirstSinger)
var selectorNameRegexp *regexp.Regexp

var selectorPatternRegexpStrMap = map[string]string{
    Sharding:       `^\s*Sharding\s*,\s*\[\s*(?P<shard_num_list>(?:\d+\s*,\s*)*(?:\d+\s*)?)\]\s*,\s*(?P<shard_cnt>\d+)\s*$`,                                                                                                                                       // such as "Sharding, [1,4], 5"
    SpecificSinger: `^\s*SpecificSinger\s*,\s*\[\s*(?P<pod_ip_list>(?:(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})){3})\s*,\s*)*(?:(?:(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})(?:\.(?:25[0-5]|2[0-4]\d|[0-1]?\d{1,2})){3})\s*)?)\]\s*$`, // such as "SpecificSinger, [192.168.0.1, 192.168.0.2]"
}
var selectorPatternRegexpMap = make(map[string]*regexp.Regexp, len(selectorPatternRegexpStrMap))

// ParseAndSetSingerSelector parse and set singer selector to SingingPlan
func ParseAndSetSingerSelector(task *task.Task, plan *planner.SingingPlan) {
    if selectorNameRegexp == nil {
        compile, err := regexp.Compile(selectorNameRegexpStr)
        selectorNameRegexp = compile
        if err != nil {
            panic(err)
        }
    }
    selectorName := selectorNameRegexp.FindStringSubmatch(task.SingerSelector)[1]
    switch selectorName {
    case AllSinger:
        plan.SingerSelector = &planner.SingingPlan_SelectAllSinger{SelectAllSinger: &planner.SingerSelector_AllSinger{}}
    case NoSinger:
        plan.SingerSelector = &planner.SingingPlan_SelectNoSinger{SelectNoSinger: &planner.SingerSelector_NoSinger{}}
    case OneRandomSinger:
        plan.SingerSelector = &planner.SingingPlan_SelectOneRandomSinger{SelectOneRandomSinger: &planner.SingerSelector_OneRandomSinger{}}
    case Sharding:
        regex, ok := selectorPatternRegexpMap[Sharding]
        if !ok {
            str := selectorPatternRegexpStrMap[Sharding]
            var err error
            regex, err = regexp.Compile(str)
            if err != nil {
                panic(err)
            }
            selectorPatternRegexpMap[Sharding] = regex
        }

        submatch := regex.FindStringSubmatch(task.SingerSelector)
        shardCnt := Str2int32(strings.TrimSpace(submatch[2]))

        split := strings.Split(submatch[1], ",")
        shardNumList := make([]int32, len(split))
        for i := range shardNumList {
            s := split[i]
            if s = strings.TrimSpace(s); s != "" {
                shardNumList[i] = Str2int32(s)
            }
        }

        plan.SingerSelector = &planner.SingingPlan_SelectSharding{
            SelectSharding: &planner.SingerSelector_Sharding{ShardCnt: shardCnt, ShardNumList: shardNumList},
        }
    case SpecificSinger:
        regex, ok := selectorPatternRegexpMap[SpecificSinger]
        if !ok {
            str := selectorPatternRegexpStrMap[SpecificSinger]
            var err error
            regex, err = regexp.Compile(str)
            if err != nil {
                panic(err)
            }
            selectorPatternRegexpMap[SpecificSinger] = regex
        }

        submatch := regex.FindStringSubmatch(task.SingerSelector)
        var podIp []string
        for _, s := range strings.Split(submatch[1], ",") {
            if s = strings.TrimSpace(s); s != "" {
                podIp = append(podIp, s)
            }
        }

        plan.SingerSelector = &planner.SingingPlan_SelectSpecificSinger{
            SelectSpecificSinger: &planner.SingerSelector_SpecificSinger{SingerIpList: podIp},
        }
    case TheFirstSinger:
        plan.SingerSelector = &planner.SingingPlan_SelectTheFirstSinger{SelectTheFirstSinger: &planner.SingerSelector_TheFirstSinger{}}
    }
}
